package com.haixiaoke.flat.order.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.haixiaoke.auth.AuthCheck;
import com.haixiaoke.saas.apartment.service.IHousingAllocationService;
import com.haixiaoke.saas.common.annotation.RepeatSubmit;
import com.haixiaoke.saas.common.config.WeChatConfig;
import com.haixiaoke.saas.common.constant.OrderConstants;
import com.haixiaoke.saas.common.core.domain.AjaxResult;
import com.haixiaoke.saas.common.core.page.TableDataInfo;
import com.haixiaoke.saas.common.core.redis.RedisCache;
import com.haixiaoke.saas.common.enums.OrderStateEnum;
import com.haixiaoke.saas.common.utils.DateUtils;
import com.haixiaoke.saas.common.weChat.domain.UnifiedOrder;
import com.haixiaoke.saas.common.weChat.service.WeChatService;
import com.haixiaoke.saas.department.domain.WechatAccount;
import com.haixiaoke.saas.department.service.IWechatAccountService;
import com.haixiaoke.saas.order.domain.*;
import com.haixiaoke.saas.order.service.ICheckOutOrderService;
import com.haixiaoke.saas.order.service.IOrderService;
import com.haixiaoke.saas.system.BaseController;
import com.haixiaoke.saas.user.domain.CheckInPerson;
import com.haixiaoke.saas.user.domain.UserConsumer;
import com.haixiaoke.saas.user.service.ICheckInPersonService;
import com.haixiaoke.saas.user.service.IUserConsumerService;
import com.haixiaoke.token.FrontTokenComponent;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 订单Controller
 *
 * @Author panda
 * @Date 2024/4/9
 **/
@RestController
@RequestMapping("/front/order/order")
public class FlatOrderController extends BaseController {
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private ICheckInPersonService checkInPersonService;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private IWechatAccountService wechatAccountService;
    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private FrontTokenComponent frontTokenComponent;
    @Autowired
    private ICheckOutOrderService checkOutOrderService;
    @Autowired
    private IUserConsumerService userConsumerService;
    @Autowired
    private IHousingAllocationService housingAllocationService;

    /**
     * 根据登录用户查询订单
     *
     * @param order
     * @return
     */
    @AuthCheck
    @GetMapping("/pageByUser")
    public TableDataInfo pageByUser(Order order) {
        startPage();
        order.setReserveUserId(frontTokenComponent.getUserId());
        List<Order> orderList = orderService.selectOrderByUserId(order);
        return getDataTable(orderList);
    }

    /**
     * 根据登录用户查询退款订单列表
     *
     * @param order
     * @return
     */
    @AuthCheck
    @GetMapping("/refund/pageByUser")
    public TableDataInfo refundPageByUser(Order order) {
        startPage();
        order.setReserveUserId(frontTokenComponent.getUserId());
        List<Order> orderList = orderService.selectRefundOrderByUserId(order);
        return getDataTable(orderList);
    }

    /**
     * 根据登录用户查询订单详情
     *
     * @param orderId
     * @return
     */
    @AuthCheck
    @GetMapping("/getInfoByUser/{orderId}")
    public AjaxResult getInfo(@PathVariable String orderId) {
        return success(orderService.miniSelectOrderByOrderId(orderId));
    }

    /**
     * 根据登录用户查询退款订单详情
     *
     * @param orderId
     * @return
     */
    @AuthCheck
    @GetMapping("/refund/getInfoByUser/{orderId}")
    public AjaxResult getRefundByUser(@PathVariable String orderId) {
        return success(orderService.miniSelectRefundOrderByOrderId(orderId));
    }

    /**
     * 查询下单所需数据
     *
     * @param houseId
     * @return
     */
    @AuthCheck
    @GetMapping("/confirmation/{houseId}")
    public AjaxResult confirmation(@PathVariable String houseId) {
        ConfirmationVO vo = orderService.confirmation(houseId);
        if (ObjectUtil.isNotEmpty(vo)) {
            String orderId = "O" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 100000);
            vo.setOrderId(orderId);
            //缓存十分钟
            redisCache.setCacheObject(OrderConstants.REDIS_ORDER_KEY + orderId, JSONObject.toJSONString(vo), 10, TimeUnit.MINUTES);
            CheckInPerson checkInPerson = checkInPersonService.selectDefaultPersonByUserId(frontTokenComponent.getUserId());
            vo.setCheckInPerson(checkInPerson);
            vo.setCalendarPriceList(null);
            vo.setUnsubscribeRule(null);
        }
        if (ObjectUtil.isEmpty(vo)) {
            return error("数据获取失败");
        }
        return success(vo);
    }

    /**
     * 计算未支付订单金额明细
     */
    @AuthCheck
    @PostMapping("/compute")
    public AjaxResult compute(@RequestBody OrderDTO dto) {
        if (StrUtil.isBlank(dto.getOrderId())) {
            return error("数据异常");
        }
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            return error("请选择时间");
        }
        if (dto.getStartTime().after(dto.getEndTime())) {
            return error("时间数据错误");
        }
        String redisKey = OrderConstants.REDIS_ORDER_KEY + dto.getOrderId();
        if (!redisCache.hasKey(redisKey)) {
            return error("房屋数据已过期，请重新预订");
        }
        String cacheObject = redisCache.getCacheObject(redisKey);
        ConfirmationVO vo = JSONObject.parseObject(cacheObject, ConfirmationVO.class);
        if (DateUtil.betweenDay(dto.getStartTime(), dto.getEndTime(), false) < vo.getHousingAllocation().getLeaseIntervalDay()) {
            return error("预订时间少于房屋预订天数标准");
        }
        ConfirmationVO compute = orderService.compute(dto.getStartTime(), dto.getEndTime(), dto.getOrderId(), null, vo.getHousingAllocation(), vo.getHousingPriceList(), false, null);
        return success(compute);
    }

    /**
     * 下单
     *
     * @param dto
     * @return
     */
    @AuthCheck
    @RepeatSubmit
    @PostMapping("/placeOrder")
    public AjaxResult placeOrder(@RequestBody OrderDTO dto) {
        if (StrUtil.isBlank(dto.getOrderId())) {
            return error("数据异常");
        }

        UserConsumer userConsumer = userConsumerService.selectUserConsumerByUserId(frontTokenComponent.getUserIdNotNull());
        if (ObjectUtil.isEmpty(userConsumer) || ObjectUtil.isEmpty(userConsumer.getOpenId())) {
            return error("用户数据异常");
        }
        dto.setOpenId(userConsumer.getOpenId());
        if (dto.getLesseeId() == null) {
            return error("请选择承租人");
        }
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            return error("请选择时间");
        }
        if (dto.getStartTime().after(dto.getEndTime())) {
            return error("时间数据错误");
        }
        String redisKey = OrderConstants.REDIS_ORDER_KEY + dto.getOrderId();
        if (!redisCache.hasKey(redisKey)) {
            return error("房屋数据已过期，请重新预订");
        }
        String cacheObject = redisCache.getCacheObject(redisKey);
        ConfirmationVO vo = JSONObject.parseObject(cacheObject, ConfirmationVO.class);
        if (DateUtil.betweenDay(dto.getStartTime(), dto.getEndTime(), false) < vo.getHousingAllocation().getLeaseIntervalDay()) {
            return error("预订时间少于房屋预订天数标准");
        }
        if (housingAllocationService.checkTimeRange(vo.getHousingAllocation().getHouseId(), dto.getEndTime())) {
            return error("该房屋已超过预定范围时间");
        }
        if (CollectionUtil.isEmpty(dto.getMemberIdList())) {
            if (vo.getHouse().getCheckInNumber() < 1) {
                return error("入住人数已超过房屋最大人数");
            }
            dto.setMemberIdList(new ArrayList<>());
        } else {
            if (vo.getHouse().getCheckInNumber() < dto.getMemberIdList().size() + 1) {
                return error("入住人数已超过房屋最大人数");
            }
        }
        Order newOrder = new Order();
        newOrder.setCheckInTime(dto.getStartTime());
        newOrder.setCheckOutTime(dto.getEndTime());
        newOrder.setHouseId(vo.getHousingAllocation().getHouseId());
        if (orderService.checkRepeatOrder(newOrder)) {
            return error("该时间段内已被租赁");
        }
        WechatAccount account = wechatAccountService.selectWechatAccountByTenantId(vo.getHouse().getTenantId());
        if (ObjectUtil.isEmpty(account)) {
            return error("商家信息错误，请联系管理员");
        }
        UserConsumer user = frontTokenComponent.getLoginUser().getUser();
        dto.setUserConsumer(user);
        //下单
        Order order = orderService.placeOrder(dto, vo);
        redisCache.setCacheObject(OrderConstants.REDIS_OBLIGATION_ORDER_KEY + order.getOrderId(), order, 15, TimeUnit.MINUTES);
        UnifiedOrder unifiedOrder = getUnifiedOrder(dto, account, order);
        return weChatService.unifiedOrder(unifiedOrder);
    }

    /**
     * 未支付订单再次支付
     *
     * @param orderDTO
     * @return
     */
    @AuthCheck
    @RepeatSubmit
    @PostMapping("/orderPay")
    public AjaxResult orderPay(@RequestBody OrderDTO orderDTO) {
        Order order = orderService.selectOrderById(orderDTO.getOrderId());
        if (ObjectUtil.isEmpty(order)) {
            return error("订单数据异常");
        }
        //只有未支付、续租-未支付订单能支付
        if (!(OrderStateEnum.ORDER_STATE_OBLIGATION.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_RELET_OBLIGATION.getValue().equals(order.getOrderState()))) {
            return error("该订单已支付");
        }
        UserConsumer userConsumer = userConsumerService.selectUserConsumerByUserId(frontTokenComponent.getUserIdNotNull());
        if (ObjectUtil.isEmpty(userConsumer) || StrUtil.isBlank(userConsumer.getOpenId())) {
            return error("用户数据异常");
        }
        orderDTO.setOpenId(userConsumer.getOpenId());
        WechatAccount account = wechatAccountService.selectWechatAccountByTenantId(order.getTenantId());
        if (ObjectUtil.isEmpty(account)) {
            return error("商家信息错误，请联系管理员");
        }
        UnifiedOrder unifiedOrder = getUnifiedOrder(orderDTO, account, order);
        return weChatService.unifiedOrder(unifiedOrder);
    }

    /**
     * 退房订单补缴
     *
     * @param orderDTO
     * @return
     */
    @AuthCheck
    @RepeatSubmit
    @PostMapping("/supplementaryPayment")
    public AjaxResult supplementaryPayment(@RequestBody OrderDTO orderDTO) {
        if (StrUtil.isBlank(orderDTO.getOrderId())) {
            return error("数据缺失");
        }
        Order order = orderService.selectOrderById(orderDTO.getOrderId());
        CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(order.getOrderId());
        if (ObjectUtil.isEmpty(order) || ObjectUtil.isEmpty(checkOutOrder)) {
            return error("订单数据异常");
        }
        //只有已完成订单能补缴
        if (!(OrderStateEnum.ORDER_STATE_COMPLETED.getValue().equals(order.getOrderState()) &&
                StrUtil.equals(OrderConstants.ORDER_STATE_OBLIGATION, checkOutOrder.getRefundOrderState()))) {
            return error("订单状态异常");
        }
        UserConsumer userConsumer = userConsumerService.selectUserConsumerByUserId(frontTokenComponent.getUserIdNotNull());
        if (ObjectUtil.isEmpty(userConsumer) || StrUtil.isBlank(userConsumer.getOpenId())) {
            return error("用户数据异常");
        }
        orderDTO.setOpenId(userConsumer.getOpenId());
        WechatAccount account = wechatAccountService.selectWechatAccountByTenantId(order.getTenantId());
        if (ObjectUtil.isEmpty(account)) {
            return error("商家信息错误，请联系管理员");
        }
        orderDTO.setOrderId(checkOutOrder.getCheckOutOrderId());
        UnifiedOrder unifiedOrder = getUnifiedOrder(orderDTO, account, order);
        return weChatService.unifiedOrder(unifiedOrder);
    }

    private UnifiedOrder getUnifiedOrder(OrderDTO dto, WechatAccount account, Order order) {
        UnifiedOrder unifiedOrder = new UnifiedOrder();
        unifiedOrder.setAppId(weChatConfig.getAppId());
        unifiedOrder.setOpenId(dto.getOpenId());
        unifiedOrder.setAccountId(account.getAccountId());
        unifiedOrder.setAccountApiKey(account.getAccountApiKey());
        unifiedOrder.setAttach(account.getTenantId());
        unifiedOrder.setOutTradeNo(dto.getOrderId());
        BigDecimal totalFee = BigDecimal.ZERO;
        if (OrderStateEnum.ORDER_STATE_OBLIGATION.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_RELET_OBLIGATION.getValue().equals(order.getOrderState())) {
            totalFee = order.getDeposit().add(order.getTotalRent());
            unifiedOrder.setCallBackUrl(weChatConfig.getApartmentPayCallBackUrl());
            unifiedOrder.setBody("房屋管家-公寓支付");
        } else if (StrUtil.equals(OrderStateEnum.ORDER_STATE_COMPLETED.getValue(), order.getOrderState())) {
            totalFee = order.getSupplementaryPayment();
            unifiedOrder.setCallBackUrl(weChatConfig.getSupplementaryPaymentCallBackUrl());
            unifiedOrder.setBody("房屋管家-退房补缴");
        }
        // TODO: 2024/4/22 金额写死
        unifiedOrder.setTotalFee(/*totalFee.multiply(BigDecimal.valueOf(100)).intValue()*/1);
        return unifiedOrder;
    }

    /**
     * C端用户取消订单
     *
     * @param orderId
     * @return
     */
    @GetMapping("/cancelledOrder/{orderId}")
    @AuthCheck
    @RepeatSubmit
    public AjaxResult cancelledOrder(@PathVariable String orderId) {
        Order order = orderService.selectOrderById(orderId);
        if (ObjectUtil.isEmpty(order) || !frontTokenComponent.getUserId().equals(order.getReserveUserId())) {
            return error("操作的订单数据异常");
        }
        return toAjax(orderService.frontCancelledOrder(orderId));
    }

    @AuthCheck
    @GetMapping("/countOrderState")
    public AjaxResult countOrderState() {
        return success(orderService.countOrderState(frontTokenComponent.getUserIdNotNull()));
    }

    /**
     * C端用户删除订单
     *
     * @param orderId
     * @return
     */
    @DeleteMapping("/deletedOrder/{orderId}")
    @AuthCheck
    @RepeatSubmit
    public AjaxResult deletedOrder(@PathVariable String orderId) {
        Order order = orderService.selectOrderById(orderId);
        if (ObjectUtil.isEmpty(order) || !frontTokenComponent.getUserId().equals(order.getReserveUserId())) {
            return error("操作的订单数据异常");
        }
        if (!(OrderStateEnum.ORDER_STATE_CANCEL_PAY.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_RELET_CANCEL_PAY.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_UNSUBSCRIBE_SUCCESSFULLY.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_COMPLETED.getValue().equals(order.getOrderState()))) {
            return error("当前订单状态不允许删除");
        }
        return toAjax(orderService.frontDeletedOrder(orderId));
    }

    /**
     * 校验订单是否能取消预订
     *
     * @return
     */
    @AuthCheck
    @GetMapping("/checkCancelReservation/{orderId}")
    public AjaxResult checkCancelReservation(@PathVariable String orderId) {
        Order order = orderService.selectOrderById(orderId);
        AjaxResult ajaxResult;
        if (!OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue().equals(order.getOrderState())) {
            ajaxResult = AjaxResult.error("订单状态异常，请刷新后再试");
            ajaxResult.put("title", "订单状态异常");
            return ajaxResult;
        }
        //预订结束时间在当前时间之前，则不允许退订
        if (order.getCheckOutTime().before(DateUtils.getNowDate())) {
            ajaxResult = AjaxResult.error("超出取消预订时间，若想继续进行退订操作，请联系房东");
            ajaxResult.put("title", "超出取消预订时间");
            return ajaxResult;
        }
        return success();
    }

    /**
     * 预订订单统计退款金额
     *
     * @return
     */
    @AuthCheck
    @PostMapping("/reservation/computeRefund/{orderId}")
    public AjaxResult reservationComputeRefund(@PathVariable String orderId) {
        return success(orderService.reservationComputeRefund(orderId, false));
    }

    /**
     * 预订订单取消预订
     *
     * @return
     */
    @AuthCheck
    @PostMapping("/cancelReservation")
    @RepeatSubmit
    public AjaxResult cancelReservation(@RequestBody OrderStateRecord orderStateRecord) {
        Order order = orderService.selectOrderById(orderStateRecord.getOrderId());
        AjaxResult ajaxResult;
        if (!OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue().equals(order.getOrderState())) {
            ajaxResult = AjaxResult.error("订单状态异常，请重新提交信息");
            return ajaxResult;
        }
        //预订结束时间在当前时间之前，则不允许退订
        if (order.getCheckOutTime().before(DateUtils.getNowDate())) {
            ajaxResult = AjaxResult.error("超出取消预订时间，若想继续进行退订操作，请联系房东");
            return ajaxResult;
        }
        orderStateRecord.setRecordSource(OrderConstants.RECORD_SOURCE_CONSUMER);
        return toAjax(orderService.cancelReservation(orderStateRecord, frontTokenComponent.getLoginUser().getUser().getUserName(), frontTokenComponent.getUserId(), OrderConstants.AUDIT_SOURCE_MINI_PROGRAM));
    }
}
